package zhou.chs.p6_1;

import android.content.pm.ActivityInfo;
import android.graphics.Color;
import android.os.Handler;
import android.os.Message;
import android.support.v4.app.NotificationCompatSideChannelService;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.text.Layout;
import android.view.View;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.TextView;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.Timer;
import java.util.TimerTask;

public class MainActivity extends AppCompatActivity implements View.OnClickListener{
    TextView tvH1,tvH2,tvL1,tvL2,tvL3,tvF1,tvF2,tvF3,tvSta;
    Button bt1,bt2,bt3,bt4,bt5,bt6,bt7,bt8,bt9;
    EditText et;
    private Handler myhandler;                  //声明线程myhandler
    private DatagramSocket uSocket;
    private DatagramPacket rPacket,tPacket;
    boolean running = false;
    boolean connected = false;
    private UdpThread ut;       //UDP线程
    private ReceiveThread ct;   //UDP接收线程
    String strSta;
    int tn=0; //延时3秒自动退出操作状态
    int tm=0; //通信计数
    int Sta=0; //状态：特定值发送对应命令，=0时读取状态
    int setf1=0,setf2=0,setf3=0; //3个变频器的设定频率
    int setf; //设定频率
    private byte rbuf[] = new byte[128];		//接收缓冲区
    private byte tbuf[] = new byte[8];		//发送缓冲区
    int crc16;
    private int len;    //接收数据长度
    boolean next = false;  //当Sta=0时，轮流读取开关量状态和模拟量状态
    //写开关量，开关量模块通信地址为1
    byte[] writeDO = {(byte) 0x01, (byte) 0x05, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0xFF, (byte) 0xFF};
    //读开关量
    byte[] readDI = {(byte) 0x01, (byte) 0x02, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x10, (byte) 0x79, (byte) 0xC6};
    //写变频频率，填写频率,计算CRC
    byte[] writeAO = {(byte) 0x02, (byte) 0x06, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0xFF, (byte) 0xFF};
    //读模拟量，通信地址2，读取10路AI
    byte[] readAI = {(byte) 0x02, (byte) 0x04, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x0A, (byte) 0x70, (byte) 0x3E};
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //强制横屏
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
        //屏幕常亮
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
        init();     //控件初始化
        myhandler = new MyHandler();        //新建Handler，用于线程间的通信
        Timer mTimer = new Timer();         //新建Timer
        mTimer.schedule(new TimerTask() {
            @Override
            public void run() {
                tn++;                   //每秒加1
                Message msg = myhandler.obtainMessage();   //创建消息
                msg.what = 1;                      //变量what赋值
                myhandler.sendMessage(msg);     //发送消息
            }
        }, 3000, 500);     //延时3000ms，然后每隔500ms发送消息
    }
        //处理接收到的消息
    class MyHandler extends Handler {
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case 1: //定时
                    if(tn>15){
                        if(tn==16){
                            Sta=0;
                            tvSta.setText("操作取消！");
                            et.setVisibility(View.INVISIBLE);
                            bt8.setVisibility(View.INVISIBLE);
                            bt9.setVisibility(View.INVISIBLE);
                        }
                        tn=20;
                    }
                    if(connected){
                        if (Sta == 0) {  //轮流读取AI和DI
                            next = !next;
                            if (next) tbuf = readDI;
                            else tbuf = readAI;
                        }
                        if ((Sta >= 17) && (Sta <= 23)) { //输出0
                            writeDO[3] = (byte) ((Sta - 17) & 0xFF);
                            writeDO[4] = (byte) (0xFF);
                            crc16 = CRC16(writeDO, 6);
                            writeDO[6] = (byte) (crc16 & 0xFF);
                            writeDO[7] = (byte) (crc16 >> 8);
                            tbuf = writeDO;
                        }
                        if ((Sta >= 33) && (Sta <= 39)) { //输出1
                            writeDO[3] = (byte) ((Sta - 33) & 0xFF);
                            writeDO[4] = (byte) (0x00);
                            crc16 = CRC16(writeDO, 6);
                            writeDO[6] = (byte) (crc16 & 0xFF);
                            writeDO[7] = (byte) (crc16 >> 8);
                            tbuf = writeDO;
                        }
                        if (Sta == 40) {    //写1#加药泵频率
                            writeAO[3] = (byte) (0x00);
                            writeAO[4] = (byte) (setf1 >> 8);
                            writeAO[5] = (byte) (setf1 & 0xFF);
                            crc16 = CRC16(writeAO, 6);
                            writeAO[6] = (byte) (crc16 & 0xFF);
                            writeAO[7] = (byte) (crc16 >> 8);
                            tbuf = writeAO;
                        }
                        if (Sta == 41) {    //写2#加药泵频率
                            writeAO[3] = (byte) (0x01);
                            writeAO[4] = (byte) (setf2 >> 8);
                            writeAO[5] = (byte) (setf2 & 0xFF);
                            crc16 = CRC16(writeAO, 6);
                            writeAO[6] = (byte) (crc16 & 0xFF);
                            writeAO[7] = (byte) (crc16 >> 8);
                            tbuf = writeAO;
                        }
                        if (Sta == 42) {    //写供水泵频率
                            writeAO[3] = (byte) (0x02);
                            writeAO[4] = (byte) (setf3 >> 8);
                            writeAO[5] = (byte) (setf3 & 0xFF);
                            crc16 = CRC16(writeAO, 6);
                            writeAO[6] = (byte) (crc16 & 0xFF);
                            writeAO[7] = (byte) (crc16 >> 8);
                            tbuf = writeAO;
                        }
                        if(Sta>10) Sta=0;
                        tPacket = null;
                        try {
                            tPacket = new DatagramPacket(tbuf, 8);
                            uSocket.send(tPacket);  //UDP连接发送数据
                        } catch (Exception e) {
                        }

                    }
                    break;
                case 2: //收到数据
                    if((rbuf[0]==0x01) && (rbuf[1]==0x02))		//输入寄存器状态
                    {
                        crc16=CRC16(rbuf,5);
                        if(((rbuf[5]&0xFF)==(crc16&0xFF)) && ((rbuf[6]&0xFF)==((crc16>>8)&0xFF)))
                        {
                            int m = rbuf[3];
                            if((m&0x01)==1) bt1.setTextColor(Color.RED);
                            else bt1.setTextColor(Color.GREEN);
                            if((m&0x02)==2) bt2.setTextColor(Color.RED);
                            else bt2.setTextColor(Color.GREEN);
                            if((m&0x04)==4) bt3.setTextColor(Color.RED);
                            else bt3.setTextColor(Color.GREEN);
                            if((m&0x08)==8) bt4.setTextColor(Color.RED);
                            else bt4.setTextColor(Color.GREEN);
                            if((m&0x10)==16) bt5.setTextColor(Color.RED);
                            else bt5.setTextColor(Color.GREEN);
                            if((m&0x20)==0) bt6.setTextColor(Color.RED);
                            else bt6.setTextColor(Color.GREEN);
                            if((m&0x40)==0) bt7.setTextColor(Color.RED);
                            else bt7.setTextColor(Color.GREEN);
                        }
                    }
                    if((rbuf[0]==0x02) && (rbuf[1]==0x04))		//模拟量
                    {
                        crc16=CRC16(rbuf,23);
                        if(((rbuf[23]&0xFF)==(crc16&0xFF)) && ((rbuf[24]&0xFF)==((crc16>>8)&0xFF)))
                        {
                            int m[] = new int[10];
                            for(int i=0;i<10;i++) {
                                m[i]=(rbuf[2*i+3]<<8)|(rbuf[2*i+4]&0xFF);
                            }
                            tvH1.setText(String.format("%.1f",(float)(15.0*m[8]/3276-3.75)) );         //液位1
                            tvH2.setText(String.format("%.1f",(float)(15.0*m[9]/3276-3.75)) );         //液位2
                            tvL1.setText(String.format("%.2f",(float)(10.0*m[4]/3276-2.5)) );         //流量1
                            tvL2.setText(String.format("%.2f",(float)(10.0*m[5]/3276-2.5)) );         //流量2
                            tvL3.setText(String.format("%.2f",(float)(10.0*m[6]/3276-2.5)) );         //流量3
                            tvF1.setText(String.format("%.0f",(float)(50.0*m[0]/4096)) );         //变频1
                            tvF2.setText(String.format("%.0f",(float)(50.0*m[1]/4096)) );         //变频2
                            tvF3.setText(String.format("%.0f",(float)(50.0*m[2]/4096)) );         //变频3
                        }
                    }
                    tm++;
                    if(tm>120) tm=0;
                    if(Sta==0){
                        tvSta.setText("通信计数：" + Integer.toString(tm));
                    }
                    break;
                case 3: //设备已连接
                    connected=true;
                    tvSta.setText("设备已连接！");
                    break;
            }
        }
    }
    //控件初始化
    public void init() {
        tvH1=findViewById(R.id.idtv1);
        tvH2=findViewById(R.id.idtv2);
        tvL1=findViewById(R.id.idtv3);
        tvL2=findViewById(R.id.idtv4);
        tvL3=findViewById(R.id.idtv5);
        tvF1=findViewById(R.id.idtv6);
        tvF2=findViewById(R.id.idtv7);
        tvF3=findViewById(R.id.idtv8);
        tvSta=findViewById(R.id.idtv);
        et=findViewById(R.id.idet);
        bt1=findViewById(R.id.idbt1);
        bt2=findViewById(R.id.idbt2);
        bt3=findViewById(R.id.idbt3);
        bt4=findViewById(R.id.idbt4);
        bt5=findViewById(R.id.idbt5);
        bt6=findViewById(R.id.idbt6);
        bt7=findViewById(R.id.idbt7);
        bt8=findViewById(R.id.idbt8);
        bt9=findViewById(R.id.idbt9);
        bt1.setOnClickListener(this);
        bt2.setOnClickListener(this);
        bt3.setOnClickListener(this);
        bt4.setOnClickListener(this);
        bt5.setOnClickListener(this);
        bt6.setOnClickListener(this);
        bt7.setOnClickListener(this);
        bt8.setOnClickListener(this);
        bt9.setOnClickListener(this);
        tvF1.setOnClickListener(this);
        tvF2.setOnClickListener(this);
        tvF3.setOnClickListener(this);
        et.setVisibility(View.INVISIBLE);
        bt8.setVisibility(View.INVISIBLE);
        //bt9.setVisibility(View.INVISIBLE);
    }
    //操作区为启停泵
    public void setCmd1() {
        tvSta.setText(strSta);
        bt8.setText("停止");
        bt9.setText("启动");
        et.setVisibility(View.INVISIBLE);
        bt8.setVisibility(View.VISIBLE);
        bt9.setVisibility(View.VISIBLE);
    }
    //操作区为开关阀门
    public void setCmd2() {
        tvSta.setText(strSta);
        bt8.setText("关闭");
        bt9.setText("打开");
        et.setVisibility(View.INVISIBLE);
        bt8.setVisibility(View.VISIBLE);
        bt9.setVisibility(View.VISIBLE);
    }
    //操作区为开关阀门
    public void setCmd3() {
        tvSta.setText(strSta);
        bt8.setText("取消");
        bt9.setText("确定");
        et.setVisibility(View.VISIBLE);
        et.setText(Integer.toString(setf));
        bt8.setVisibility(View.VISIBLE);
        bt9.setVisibility(View.VISIBLE);
    }
    @Override
    public void onClick(View view) {
        tn=0;
        switch (view.getId()){
            case R.id.idbt1:    //1#上药泵
                Sta=1;
                strSta="1#上药泵操作";
                setCmd1();
                break;
            case R.id.idbt2:    //2#上药泵
                Sta=2;
                strSta="2#上药泵操作";
                setCmd1();
                break;
            case R.id.idbt3:    //供水泵
                Sta=3;
                strSta="供水泵操作";
                setCmd1();
                break;
            case R.id.idbt4:    //1#加药泵
                Sta=4;
                strSta="1#加药泵操作";
                setCmd1();
                break;
            case R.id.idbt5:    //2#加药泵
                Sta=5;
                strSta="2#加药泵操作";
                setCmd1();
                break;
            case R.id.idbt6:    //入口阀
                Sta=6;
                strSta="入口阀操作";
                setCmd2();
                break;
            case R.id.idbt7:    //出口阀
                Sta=7;
                strSta="出口阀操作";
                setCmd2();
                break;
            case R.id.idtv6:    //1#加药泵频率
                Sta=8;
                setf=setf1;
                strSta="1#加药泵频率";
                setCmd3();
                break;
            case R.id.idtv7:    //2#加药泵频率
                Sta=9;
                setf=setf2;
                strSta="2#加药泵频率";
                setCmd3();
                break;
            case R.id.idtv8:    //供水泵频率
                Sta=10;
                setf=setf3;
                strSta="供水泵频率";
                setCmd3();
                break;
            case R.id.idbt8:    //停止/关闭/取消
                Sta=Sta|0x10;
                tvSta.setText(strSta);
                et.setVisibility(View.INVISIBLE);
                bt8.setVisibility(View.INVISIBLE);
                bt9.setVisibility(View.INVISIBLE);
                break;
            case R.id.idbt9:    //启动/打开/确定
                if(Sta == 0){
                    ut = new UdpThread();
                    ut.start();  //进入UDP连接线程
                    bt9.setVisibility(View.INVISIBLE);
                }else {
                    Sta = Sta | 0x20;
                    tvSta.setText(strSta);
                    et.setVisibility(View.INVISIBLE);
                    bt8.setVisibility(View.INVISIBLE);
                    bt9.setVisibility(View.INVISIBLE);
                    if(Sta==40) setf1=Integer.parseInt(et.getText().toString());
                    if(Sta==41) setf2=Integer.parseInt(et.getText().toString());
                    if(Sta==42) setf3=Integer.parseInt(et.getText().toString());
                }
                break;
        }
    }
    //CRC校验，
    int CRC16(byte dat[],int len)
    {
        int CRC=0xFFFF;
        int temp;
        int i,j;
        for( i = 0; i<len; i ++)
        {
            temp = dat[i];
            if(temp < 0) temp += 256;
            temp &= 0xFF;
            CRC^= temp;
            for (j = 0; j<8; j++)
            {
                if ((CRC & 0x0001) == 0x0001)
                   CRC=(CRC>>1)^0xA001;
                else
                    CRC >>=1;
            }
        }
        return (CRC&0xFFFF);
    }
    // UDP连接线程
    private class UdpThread extends Thread{
        public void run() {
            try {
                uSocket = new DatagramSocket(6000);  //绑定本地端口为6000
                //建立UDP连接，参数为对侧IP地址和端口
                uSocket.connect(InetAddress.getByName("10.10.100.254"), 8899);
                running=true;
                Message msg = myhandler.obtainMessage();
                msg.what = 3;
                myhandler.sendMessage(msg);
                ct = new ReceiveThread();
                ct.start();     //运行接收UDP数据线程
            } catch (Exception e) {
            }
        }
    }
    // UDP数据接收线程
    private class ReceiveThread extends Thread{
        @Override
        public void run() {
            int byt; // bytes returned from read()
            byte buf[] = new byte[128];
            while (running) {
                rPacket = null;
                try {
                    rPacket = new DatagramPacket(buf, buf.length);
                    uSocket.receive(rPacket);   //接收数据
                    byt=rPacket.getLength();
                    if(byt>0){    //收到数据
                        for(int i=0;i<byt;i++) rbuf[i]=buf[i];
                        Message msg = myhandler.obtainMessage();
                        msg.what = 2;
                        msg.obj=byt;
                        myhandler.sendMessage(msg); // 通知主线程接收到数据
                        try{
                            sleep(100);
                        }catch (InterruptedException e){
                            e.printStackTrace();
                        }
                    }
                } catch (NullPointerException e) {
                    running = false;//防止服务器端关闭导致客户端读到空指针而导致程序崩溃
                    e.printStackTrace();
                    break;
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
